/**
 * @file eigen.h
 * @brief 3维变量以及3x3矩阵
 * @note
 */

#ifndef EIGEN_H // 防止重复包含
#define EIGEN_H

#ifdef __cplusplus // C++兼容性声明
extern "C"
{
#endif

#include <assert.h>
#include <float.h>
#include <math.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define INF DBL_MAX // 表示无穷大的双精度值

    // ==================== 三维向量计算以及动态三维向量 ====================

    /// @brief 三维双精度向量
    typedef struct
    {
        double x;
        double y;
        double z;
    } Vector3d;

    /**
     * @brief 向量加法:result = a + b
     * @param a 输入向量A
     * @param b 输入向量B
     * @param[out] result 计算结果向量
     */
    void vector3d_add(const Vector3d *a, const Vector3d *b, Vector3d *result);

    /**
     * @brief 向量减法:result = a - b
     * @param a 输入向量A
     * @param b 输入向量B
     * @param[out] result 计算结果向量
     */
    void vector3d_sub(const Vector3d *a, const Vector3d *b, Vector3d *result);

    /**
     * @brief 向量点积
     * @param a 输入向量A
     * @param b 输入向量B
     * @return 点积值(double)
     * @note 可用于计算夹角:a·b = |a||b|cosθ
     */
    double vector3d_dot(const Vector3d *a, const Vector3d *b);

    /**
     * @brief 向量叉积
     * @param a 输入向量A
     * @param b 输入向量B
     * @param[out] result 叉积向量
     * @note 结果向量垂直于a和b构成的平面
     */
    void vector3d_cross(const Vector3d *a, const Vector3d *b, Vector3d *result);

    /**
     * @brief 计算向量范数(模长)
     * @param v 输入向量
     * @return 范数值(double)
     */
    double vector3d_norm(const Vector3d *v);

    /**
     * @brief 向量归一化(原地修改)
     * @param[in,out] v 待归一化向量指针
     * @note 零向量将被保留不变
     */
    void vector3d_normalize(Vector3d *v);

    /**
     * @brief 向量数乘
     * @param v 输入向量
     * @param scalar 比例因子
     * @param[out] result 缩放后的向量
     */
    void vector3d_scale(const Vector3d *v, double scalar, Vector3d *result);

    /**
     * @brief 判断向量是否近似为零
     * @param v 输入向量
     * @param epsilon 容差阈值
     * @return true表示所有分量绝对值均小于tol
     */
    bool vector3d_is_zero(const Vector3d *v, double epsilon);

    // ==================== 3x3 矩阵 ====================

    /// @brief 3x3双精度矩阵
    typedef struct
    {
        double data[3][3];
    } Matrix3d;

    // ==================== 3x3矩阵操作 ====================
    /**
     * @brief 3x3矩阵与3D向量相乘
     * @param m 输入矩阵(3x3)
     * @param v 输入向量
     * @param[out] result 输出结果向量
     * @note 常用于坐标变换:v' = M*v
     */
    void matrix3d_mul_vector3d(const Matrix3d *m, const Vector3d *v, Vector3d *result);

    /**
     * @brief 3x3矩阵乘法:result = a * b
     * @param a 输入矩阵A(3x3)
     * @param b 输入矩阵B(3x3)
     * @param[out] result 输出结果矩阵
     * @note 不支持原地计算(result不能与a或b相同)
     */
    void matrix_multiply_3x3(const Matrix3d *a, const Matrix3d *b, Matrix3d *result);

    /**
     * @brief 3x3矩阵转置:result = a^T
     * @param a 输入矩阵(3x3)
     * @param[out] result 输出转置矩阵
     * @note 支持原地转置(result可与a相同)
     */
    void matrix_transpose_3x3(const Matrix3d *a, Matrix3d *result);

    /**
     * @brief 3x3矩阵求逆(基于伴随矩阵法)
     * @param a 输入矩阵(3x3)
     * @param[out] result 输出逆矩阵
     * @note 对于奇异矩阵会返回单位矩阵并保持result不变
     */
    void matrix_inverse_3x3(const Matrix3d *a, Matrix3d *result);

    /**
     * @brief 设置3x3单位矩阵
     * @param[out] m 目标矩阵指针
     */
    void matrix3d_set_identity(Matrix3d *m);

    /**
     * @brief 从二维数组初始化Matrix3d
     * @param[out] m 目标矩阵指针
     * @param data 源数据数组[3][3]
     * @note 数据按行优先顺序拷贝
     */
    void matrix3d_from_array(Matrix3d *m, const double data[3][3]);

#ifdef __cplusplus
}
#endif

#endif // EIGEN_H